Skip to content

fix(process): kill the whole process group on teardown; per-slug tmux env preamble#18

Merged
hefgi merged 2 commits into
mainfrom
claude/magical-einstein-7m4g40-process
Jun 11, 2026
Merged

fix(process): kill the whole process group on teardown; per-slug tmux env preamble#18
hefgi merged 2 commits into
mainfrom
claude/magical-einstein-7m4g40-process

Conversation

@hefgi

@hefgi hefgi commented Jun 10, 2026

Copy link
Copy Markdown
Owner

Fixes #3

Process-group kill (orphaned services)

spawn_nohup runs each service as sh -c <cmd> in its own process group (process_group(0)) — but kill_nohup sent SIGTERM to the single stored PID. For any compound command the sh wrapper died while the actual dev server survived, kept the port bound, and pushed the next up onto a silently auto-bumped port.

Per-slug env preamble (cross-session port leak)

The tmux env preamble was a single shared .ecluse/env-preamble.sh, overwritten by every session's spawn. Re-running the setup line in session A's tmux window (the manual-restart workflow the file exists for) after session B came up sourced B's ports into A's service — an isolation break in the env-injection mechanism itself.

  • preamble now lives at .ecluse/preambles/<slug>.sh
  • host/hybrid bring_down delete the session's preamble; flush wipes the preambles dir
  • consolidated the thrice-duplicated .ecluse-ancestor lookup into ecluse_dir_for

Tests

  • kill_nohup_kills_whole_process_group — service spawns a background child; teardown must kill it (fails on the old single-PID kill)
  • spawn_nohup_partial_failure_cleans_up_already_spawned
  • env_preamble_file_is_namespaced_per_slug, remove_env_preamble_deletes_only_that_slug

cargo fmt --check, cargo clippy -- -D warnings, cargo test (373 + 18) green.

https://claude.ai/code/session_017UcuvzMKHVfyBCcq8ipAko


Generated by Claude Code

claude added 2 commits June 10, 2026 23:56
… slug

kill_nohup signaled only the stored PID. Services spawn as 'sh -c <cmd>'
in their own process group (process_group(0)) — TERM to the leader killed
the wrapper while the actual server survived, kept the port bound, and
forced the next up onto an auto-bumped port. Teardown now TERMs the whole
group and escalates to KILL after a 2s grace period. spawn_nohup also
kills already-spawned services when a later spawn fails instead of
orphaning them.

The tmux env preamble was one shared .ecluse/env-preamble.sh overwritten
by every session's spawn; re-running the setup line in session A's window
after session B came up sourced B's ports. The preamble now lives at
.ecluse/preambles/<slug>.sh.

Fixes #3

https://claude.ai/code/session_017UcuvzMKHVfyBCcq8ipAko
@hefgi hefgi merged commit 167ef69 into main Jun 11, 2026
2 checks passed
hefgi added a commit that referenced this pull request Jun 15, 2026
* fix(process): use `./` prefix when sourcing env files in tmux for zsh

zsh's POSIX `.` builtin does not search the current directory unless
`.` is in `$PATH` — the default macOS shell is zsh, so the bare
`. '.env'` form silently failed there with "no such file or directory"
even after the cd-first fix from #18. Services in tmux windows ended
up without the per-slot env: `ECLUSE_*` vars from the per-slug preamble
were fine, but anything from `.env`, `.env.local`, or `.env.ecluse`
that wasn't duplicated into the preamble was lost.

build_source_preamble now emits `. './.env'` (and the same for
`.env.local`/`.env.ecluse`). The `./` prefix is POSIX-correct and works
in bash, zsh, and dash. Adds three regression tests covering the
correct prefix, the missing-files-skip behavior, and the empty-tree
case.

Fixes #27

* fix(env): strip outer dotenv quotes when parsing .env files

parse_env_file treated everything after `=` as the literal value,
which round-tripped `FOO="bar"` as the 5-character value `"bar"`
(quotes included) when the value got re-emitted in the per-slug
tmux preamble as `export FOO='"bar"'`. Downstream consumers that
check against a literal string (e.g. `z.literal("development")`)
would reject the quoted value, breaking any framework using
conventional dotenv `KEY="value"` style.

A matched outer pair of `"..."` or `'...'` is now stripped — the
standard dotenv convention where `FOO=bar` and `FOO="bar"` mean the
same thing. Unmatched quotes (`FOO="oops`), inner escaped quotes
(`MSG="hello \"world\""`), and unquoted values containing literal
quote chars or `=` (`URL=postgres://x:5433/db?a=b`) are preserved
verbatim, so URLs and query strings round-trip unchanged.

Adds seven regression tests covering double, single, unquoted,
unmatched, inner-escaped, empty-quoted, and bare-quote-char cases.

Fixes #28

* docs: changelog entries for #27 and #28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Process lifecycle breaks isolation: kill_nohup orphans service children, and the shared tmux env-preamble leaks ports between sessions

2 participants